use spacetimedb_codegen::{generate, Csharp, Rust, TypeScript};
use spacetimedb_data_structures::map::HashMap;
use spacetimedb_schema::def::ModuleDef;
use spacetimedb_testing::modules::{CompilationMode, CompiledModule};
use std::sync::OnceLock;

fn compiled_module() -> &'static ModuleDef {
    static COMPILED_MODULE: OnceLock<ModuleDef> = OnceLock::new();
    COMPILED_MODULE
        .get_or_init(|| CompiledModule::compile("module-test", CompilationMode::Debug).extract_schema_blocking())
}

macro_rules! declare_tests {
    ($($name:ident => $lang:expr,)*) => ($(
        #[test]
        fn $name() {
            let module = compiled_module();
            let outfiles = generate(&module, &$lang)
                .into_iter()
                .map(|f| (f.filename, f.code))
                .collect::<HashMap<_, _>>();
            let mut settings = insta::Settings::clone_current();
            settings.set_sort_maps(true);
            // Ignore the autogenerated comments with version info, since it changes with every
            // build.
            settings.add_filter(r"// This was generated using spacetimedb cli version \d+\.\d+\.\d+ .*", "VERSION_COMMENT");
            // Ignore the place where the CLI version is put in the typescript REMOTE_MODULE info,
            // so it isn't constantly changing.
            settings.add_filter(r#"cliVersion: "\d+\.\d+\.\d+","#, r#"cliVersion: "X.Y.Z","#);
            settings.bind(|| {
                insta::assert_toml_snapshot!(outfiles);
            });
        }
    )*);
}

declare_tests! {
    test_codegen_csharp => Csharp { namespace: "SpacetimeDB" },
    test_codegen_typescript => TypeScript,
    test_codegen_rust => Rust,
}
